package com.frinder.base.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;

/**
 * @ClassName Server
 * @Description netty 服务端
 * @Author frinder
 * @Date 2018/11/28 19:34
 * @Version 1.0
 */
@Slf4j
public class Server {

    /**
     * 记录所有连接客户端
     */
    protected final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * boss 接收客户端连接
     */
    private final EventLoopGroup bossGroup = new NioEventLoopGroup();

    /**
     * worker 处理已连接客户端请求
     */
    private final EventLoopGroup workerGroup = new NioEventLoopGroup();

    /**
     * 保存 channel
     */
    private Channel channel;

    @Value("${port:8888}")
    private int port = 8888;

    public ChannelInitializer getServerChannelInitializer() {
        return new ServerInitializer(channels);
    }

    /**
     * 开启 netty server
     *
     * @return
     * @throws Exception
     */
    public void start() {
        log.info("*** 准备启动 Netty Server！");
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    // 注册处理链
                    .childHandler(getServerChannelInitializer())
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            channel = serverBootstrap.bind(port).syncUninterruptibly().channel();
            log.info("*** Netty Server 启动成功！");
        } catch (Exception e) {
            log.error("*** Netty Server 启动失败！", e.getMessage(), e);
            destroy();
        }
    }

    /**
     * shutdown server
     */
    public void destroy() {
        if (null != channel) {
            channel.close();
        }
        channels.close();
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
    }
}
